#include "myserialport.h"
#include <QDebug>
#include <QTextCodec>
#include <QMessageBox>
#include <QDateTime>

MySerialPort::MySerialPort()
{
    //实例化串口
    //因为串口作为独立线程运行 不要指定父类
    this->m_SerialPort = new QSerialPort();
    //实例化接收读取定时器
    this->m_RecvTimer = new QTimer();

    //串口初始化
    this->m_OpenFlag = false;
    this->m_RxByteCnt = 0;
    this->m_TxByteCnt = 0;
    this->m_NeedTimeStamp = true;
    this->m_HexSendFlag = false;
    this->m_HexShowFlag = false;
    this->m_NewLineFlag = false;
    m_EncodingType = ENCODING_TYPE_GBK;

    //串口定时接收数据
    connect(m_RecvTimer, &QTimer::timeout, this, &MySerialPort::slotSerialPortRecv);
}

MySerialPort::~MySerialPort(void)
{
    this->spClose();
    delete m_SerialPort;
    delete m_RecvTimer;
    qDebug() << "SerialPort close";
}

bool MySerialPort::spOpen()
{
    bool rst;
    qDebug() << "name = " << m_SpName;
    this->m_SerialPort->setPortName(this->m_SpName);
    this->m_SerialPort->setBaudRate(this->m_BaudRate, QSerialPort::AllDirections);
    this->m_SerialPort->setDataBits(this->m_DataBit);
    this->m_SerialPort->setStopBits(this->m_StopBit);
    this->m_SerialPort->setParity(this->m_Parity);

    rst = this->m_SerialPort->open(QIODevice::ReadWrite);
    if (rst)
    {
        //情况缓存的数据 防止乱码
        this->m_SerialPort->clear(QSerialPort::AllDirections);
        this->m_OpenFlag = true;
        this->m_RecvTimer->start(10);
        qDebug() << "SerialPort open success";
    }
    else
    {
        this->m_OpenFlag = false;
        qDebug() << "SerialPort open failed";
        QMessageBox::warning(NULL,"警告","串口打开失败",QMessageBox::Yes);
    }

    return rst;
}

void MySerialPort::spClose()
{
    this->m_SerialPort->close();
    this->m_RecvTimer->stop();
    this->m_OpenFlag = false;
}

QByteArray MySerialPort::spReadAll()
{
    return this->m_SerialPort->readAll();
}

qint64 MySerialPort::spWrite(QByteArray &byteArray)
{
    QByteArray baSendData;

    //如果16进制数据发送 首先去除字符串中的空格 然后判断字符串长度 然后将2个byte拼接成1个byte
    if (this->m_HexSendFlag)
    {
        byteArray.replace(QByteArray(" "),QByteArray(""));
        if (byteArray.length() % 2 != 0)
        {
            QMessageBox::warning(NULL,"警告","数据长度错误",QMessageBox::Yes);
            return 0;
        }
        for (qint16 i = 0; i < byteArray.length(); i+=2)
        {
            baSendData[i/2] = ((byteArray[i]-'0') << 4) | (byteArray[i+1]-'0');
        }
    }
    else
    {
        baSendData = byteArray;
        if (m_NewLineFlag)
            baSendData.append("\r\n");
    }

    if (this->m_SerialPort->isOpen())
    {
        m_TxByteCnt += baSendData.length();
        return this->m_SerialPort->write(baSendData);
    }
    else
        QMessageBox::warning(NULL,"警告","串口未打开",QMessageBox::Yes);
    return 0;
}

//串口数据接收处理
void MySerialPort::slotSerialPortRecv()
{
    QByteArray lineData;
    QString time;

    if (m_SerialPort->isOpen() == false)
    {
        QMessageBox::warning(NULL,"警告","串口已关闭",QMessageBox::Yes);
        spClose();
    }

    //no data to read
    if(m_SerialPort->atEnd())
        return;

    QByteArray recvBuff;
    if (m_NeedTimeStamp == true)
        time = "[" + QDateTime::currentDateTime().toString("hh:mm:ss.zzz") + "] ";

    //按行读取缓存中的数据 如果是hex数据 则超时100ms读取
    while(m_SerialPort->canReadLine())
    {
        lineData = m_SerialPort->readLine(0);
        m_RxByteCnt += lineData.length();

        // lineData.replace(QByteArray("\r"),QByteArray(""));
        if (m_NeedTimeStamp == true)
            lineData.insert(0,time);
        recvBuff.append(lineData);
    }

    if (m_HexShowFlag)
    {
        //间隔100ms没有收到新数据 但是还有旧数据没有被读出 则读出所有旧数据
        if ((m_SerialPort->bytesAvailable() == m_BytesAvailable) && (m_BytesAvailable != 0))
        {
            if (m_NeedTimeStamp == true)
                recvBuff.insert(0,time);

            //如果hex模式接收 调用接口将hex数据转换成空格分隔的hex字符串
            QByteArray baHexShow = m_SerialPort->readAll();
            recvBuff.append(baHexShow.toHex(' '));

            m_RxByteCnt += m_BytesAvailable;
        }
        else
            m_BytesAvailable = m_SerialPort->bytesAvailable();
    }

    if (recvBuff.isEmpty())
        return;

    //字符串数据 去掉最后的\n 后边会追加段落
    if (recvBuff.at(recvBuff.length()-1) == '\n')
        recvBuff.resize(recvBuff.length()-1);
    if (recvBuff.at(recvBuff.length()-1) == '\r')
        recvBuff.resize(recvBuff.length()-1);

    //默认utf8 转 GBK 汉字显示不乱码
    QTextCodec *TextCodec = NULL;
    QString str;
    if (m_EncodingType == ENCODING_TYPE_GBK)
    {
        TextCodec = QTextCodec::codecForName("GBK");
    }
    else if (m_EncodingType == ENCODING_TYPE_UTF8)
    {
        TextCodec = QTextCodec::codecForName("UTF8");
    }
    str = TextCodec->toUnicode(recvBuff);

    emit this->signalSerialPortRecvShow(str);
}
